package com.bigzero.workflow.common.config;

import com.bigzero.workflow.common.filter.TokenAuthFilter;
import com.bigzero.workflow.common.properties.AuthProperties;
import com.bigzero.workflow.common.utils.SpringContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * Security配置
 *
 * @author fanxinxiong
 * @since 2025-02-10
 */
@Configuration
@EnableWebSecurity
@EnableConfigurationProperties(AuthProperties.class)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig{

    @Autowired
    private AuthProperties authProperties;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        AuthenticationManager authenticationManager = SpringContextUtil.getBean("authenticationManager");
        //静态资源放行集合
        List<String> permitStaticList = authProperties.getPermitStatic();
        List<String> staticList = Optional.ofNullable(permitStaticList).orElse(new ArrayList<>());

        //方法放行集合
        List<String> permitMethodList = authProperties.getPermitMethod();
        List<String> methodList = Optional.ofNullable(permitMethodList).orElse(new ArrayList<>());

        http.authorizeHttpRequests(author->author
                        .requestMatchers(staticList.toArray(new String[staticList.size()])).permitAll()
                        .requestMatchers(methodList.toArray(new String[methodList.size()])).permitAll()
                        //接口允许匿名访问(如:登录接口)
                        .requestMatchers(methodList.toArray(new String[methodList.size()])).anonymous()
                        //其他接口都需要经过验证
                        .anyRequest().authenticated()
        );

        http.addFilterBefore(new TokenAuthFilter(authenticationManager), BasicAuthenticationFilter.class);

        http.csrf(csrf -> csrf.disable());//默认csrf token 校验开启，针对 POST, PUT, PATCH
        http.formLogin(formLogin -> formLogin.disable());
        //前后端分离关闭配置登录
        http.logout(logout -> logout.disable());

        //所有的Rest服务一定要设置为无状态,以提升操作性能
        http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        //http.headers().frameOptions().sameOrigin();
        //禁用HTTP响应标头
        http.headers(headersCustomizer -> {headersCustomizer
                .cacheControl(cache -> cache.disable())
                .frameOptions(options -> options.sameOrigin());});

        //http.cors(Customizer.withDefaults());//允许跨域请求
        return http.build();
    }

    /**
     * 获取AuthenticationManager（认证管理器），登录时认证使用
     * @param authenticationConfiguration
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        //静态资源放行集合
        List<String> permitStaticList = authProperties.getPermitStatic();
        List<String> staticList = Optional.ofNullable(permitStaticList).orElse(new ArrayList<>());

        //方法放行集合
        List<String> permitMethodList = authProperties.getPermitMethod();
        List<String> methodList = Optional.ofNullable(permitMethodList).orElse(new ArrayList<>());

        return (web) -> web.ignoring().requestMatchers(staticList.toArray(new String[staticList.size()]))
                .requestMatchers(methodList.toArray(new String[methodList.size()]));
    }

}
